# -*- coding: utf-8 -*-
#enemies here!!!

import pyglet
import math
import random

import bullets
from objects import *
import music

soldier_images = {
   "idle" : (pyglet.resource.image("soldier_idle.png"),),
   #"backwards" : (pyglet.resource.image("soldier_backwards.png")),
   #"forwards" : (pyglet.resource.image("soldier_forwards.png")),
   "dying" : (pyglet.resource.image("soldier_dying-1.png"),
       pyglet.resource.image("soldier_dying-2.png"),
       pyglet.resource.image("soldier_dying-3.png")),
   "dead" : (pyglet.resource.image("soldier_dead.png"),),
   "shootf" : (pyglet.resource.image("soldier_shooting-forwards.png"),),
   "shootb" : (pyglet.resource.image("soldier_shooting-backwards.png"),),
   "walkf" : (pyglet.resource.image("soldier_walk-forwards-1.png"),
       pyglet.resource.image("soldier_walk-forwards-2.png"),
       pyglet.resource.image("soldier_walk-forwards-3.png"),
       pyglet.resource.image("soldier_walk-forwards-4.png")),
   "walkb" : (pyglet.resource.image("soldier_walk-backwards-1.png"),
       pyglet.resource.image("soldier_walk-backwards-2.png"),
       pyglet.resource.image("soldier_walk-backwards-3.png"),
       pyglet.resource.image("soldier_walk-backwards-4.png"))
    }

for i in soldier_images.itervalues():
    for img in i:
        img.anchor_x = img.width/2
        img.anchor_y = img.height/2

batch = pyglet.graphics.Batch()

class Enemy(GameObject):
    def __init__(self, x, y, image):
        try:
            image.anchor_x = image.width/2
            image.anchor_y = image.height/2
        except AttributeError:
            for frame in image.frames:
                frame.image.anchor_x = frame.image.width/2
                frame.image.anchor_y = frame.image.height/2
        self.sprite = pyglet.sprite.Sprite(image, x=x, y=y, batch=batch)
        self.targetx = None
        self.targety = None
        self.state = self.last_state = "idle"
        super(Enemy, self).__init__()

    def _move_towards(self, targetx, targety):
        deltax = self.sprite.x-targetx
        deltay = self.sprite.y-targety
        dist = math.hypot(deltax, deltay)
        if dist < self.velocity:
            factor = 1
        else:
            factor = self.velocity/dist
        return -factor*deltax, -factor*deltay

    def _update_position(self, dt):
        if self.targetx == None or self.targety == None:
            if distance((self.sprite.x, self.sprite.y),
               (World.player.sprite.x, World.player.sprite.y)) < self.engagement_zone:
                dx, dy = self._move_towards(
                World.player.sprite.x, World.player.sprite.y)
            else:
                dx, dy = self._move_towards(random.randint(-100,100),random.randint(-100,100))
        else:
            dx, dy = self._move_towards(
            self.targetx, self.targety)
        self.sprite.x += dx
        self.sprite.y += dy
        if dy > 0:
            self.state = "walkb"
        elif dy == 0 and dx == 0:
            self.state = "idle"
        else:
            self.state = "walkf"
        if self.sprite.x == self.targetx and self.sprite.y == self.targety:
            self.targetx = None
            self.targety = None

    def _get_around_buildings(self):
        lastrect = self.rect
        self.rect = self.get_rect()
        for building in World.buildings:
            if collision(self.rect, building.rect):
                self.keep_out_of(building.rect, lastrect)
                if lastrect[1] <= building.rect[0] or lastrect[0] >= \
                   building.rect[1]:
                    #coming from the side
                    #get around the trouble
                    if abs(self.sprite.x-building.rect[0]) < \
                    abs(self.sprite.x-building.rect[1]):
                        self.targetx = building.rect[0] - self.sprite.image.width * 1.1
                    else:
                        self.targetx = building.rect[1] + self.sprite.image.width * 1.1
                    if abs(World.player.sprite.y-building.rect[2]) < \
                    abs(World.player.sprite.y-building.rect[3]):
                        self.targety = building.rect[2] - self.sprite.image.height * 1.1
                    else:
                        self.targety = building.rect[3] + self.sprite.image.height * 1.1
                else:
                    #coming from the above or belove
                    #get around the trouble
                    if abs(self.sprite.y-building.rect[2]) < \
                    abs(self.sprite.y-building.rect[3]):
                        self.targety = building.rect[2] - self.sprite.image.height * 1.1
                    else:
                        self.targety = building.rect[3] + self.sprite.image.height * 1.1
                    if abs(World.player.sprite.x-building.rect[0]) < \
                    abs(World.player.sprite.x-building.rect[1]):
                        self.targetx = building.rect[0] - self.sprite.image.width * 1.1
                    else:
                        self.targetx = building.rect[1] + self.sprite.image.width * 1.1

    def _check_if_hit(self):
        for bullet in World.player_bullets:
            if collision(self.rect, bullet.rect):
                self.be_hit(bullet.damage)
                bullet.die()
                

    def update(self, dt):
        self._update_position(dt)
        self._get_around_buildings()
        self._check_if_hit()

    def die(self):
        World.enemies.remove(self)
        self.sprite.delete()

    def be_hit(self, damage):
        self.hitpoints -= damage
        if self.hitpoints <= 0:
            self.die()

class OndaKalle(Enemy):
    def __init__(self, x,y):
        self.animations = {
           "idle" : pyglet.image.Animation.from_image_sequence(soldier_images["idle"], 10),
           "dying" : pyglet.image.Animation.from_image_sequence(soldier_images["dying"], .3),
           "dead" : pyglet.image.Animation.from_image_sequence(soldier_images["dead"], 10.0),
           "shootf" : pyglet.image.Animation.from_image_sequence(soldier_images["shootf"], 10),
           "shootb" : pyglet.image.Animation.from_image_sequence(soldier_images["shootb"], 10),
           "walkf" : pyglet.image.Animation.from_image_sequence(soldier_images["walkf"], .2),
           "walkb" : pyglet.image.Animation.from_image_sequence(soldier_images["walkb"], .2)
        }
        for anim in self.animations.itervalues():
            anim.width = anim.get_max_width()
            anim.height = anim.get_max_height()
        self.velocity = 3
        self.hitpoints = 10
        self.engagement_zone = 500
        self.fire_range = 300
        self.missile_dmg = 10
        self.missile_vel = 350
        self.cooldown_counter = 0
        self.cooldown = .7

        super(OndaKalle, self).__init__(x,y,self.animations['idle'])

    def update(self, dt):
        super(OndaKalle, self).update(dt)
        if collision(self.rect, World.player.rect):
            World.player.be_hit(self.velocity)
            self.die()
        self._set_animation()
        self._fiah(dt)
    
    def _set_animation(self):
        if self.state == self.last_state:
            return
        elif self.state in self.animations:
            self.sprite.image = self.animations[self.state]
            self.last_state = self.state

    def die(self):
        World.enemies.remove(self)
        self.state = "dying"
        self._set_animation()
        music.play_sfx("death")
        @self.sprite.event
        def on_animation_end():
            self.state = "dead"
            self._set_animation()
            @self.sprite.event
            def on_animation_end():
                pass
            def kill(dt):
                self.sprite.delete()
            pyglet.clock.schedule_once(kill, 5)

    def _fiah(self,dt):
        if distance((self.sprite.x, self.sprite.y),
           (World.player.sprite.x, World.player.sprite.y)) < self.fire_range and \
           self.cooldown_counter <=0:
            rot = math.degrees(math.atan2(self.sprite.x-World.player.sprite.x, self.sprite.y-World.player.sprite.y)) - 180
            b  = bullets.Missile(self.sprite.x, self.sprite.y, 
            rot, self.missile_dmg, self.missile_vel)
            World.enemy_bullets.append(b)
            self.cooldown_counter = self.cooldown
        elif self.cooldown_counter > 0:
            self.cooldown_counter -= dt

class Turret(Enemy):
    def __init__(self, x, y):
        baseimg = pyglet.resource.image("turret-base.png")
        canimg = pyglet.resource.image("turret-cannon.png")
        baseimg.anchor_x = baseimg.width/2
        baseimg.anchor_y = baseimg.height/2
        canimg.anchor_x = canimg.width/2
        canimg.anchor_y = canimg.height/2
        self.hitpoints = 30
        self.engagement_zone = 400
        self.rot_speed = 5
        self.cooldown_counter = 0
        self.cooldown = .4
        self.missile_vel = 300
        self.missile_dmg = 30
        super(Turret, self).__init__(x, y, baseimg) 
        #nu kan jag inte ens sklriva vettiga variabelnamn :)
        self.can_has_sprite = pyglet.sprite.Sprite(canimg,x,y,batch=batch)

    def update(self, dt):
        if distance((self.sprite.x, self.sprite.y), \
           (World.player.sprite.x, World.player.sprite.y)) \
           < self.engagement_zone:
            #update rotation
            target_rotation = 270 - math.degrees(math.atan2(
                self.sprite.y-World.player.sprite.y,
                self.sprite.x-World.player.sprite.x))
            
            if self.can_has_sprite.rotation != target_rotation:
                factor = min(self.rot_speed, abs(target_rotation - self.can_has_sprite.rotation))
                self.can_has_sprite.rotation += abs(target_rotation - self.can_has_sprite.rotation) / \
                   (target_rotation - self.can_has_sprite.rotation) * factor
            
            if (self.can_has_sprite.rotation-target_rotation)%360 < 30 and \
               self.cooldown_counter <= 0:
                self._shoot()
                self.cooldown_counter = self.cooldown
            if self.cooldown_counter > 0:
                self.cooldown_counter -= dt
        self._check_if_hit()

    def _shoot(self):
        b  = bullets.Missile(self.sprite.x, self.sprite.y, 
        self.can_has_sprite.rotation, self.missile_dmg, self.missile_vel)
        World.enemy_bullets.append(b)

    def die(self):
        bullets.do_explosion(self.sprite.x, self.sprite.y)
        super(Turret, self).die()

enemy_types = {"soldier": OndaKalle,
               "turret": Turret,
               }
